﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using log4net;

namespace ResxCrunch.Business.Managers
{
    /// <summary>
    /// Class for file operations
    /// </summary>
    public class FileMngr
    {
        #region Attributes
        #endregion Attributes

        #region Constants
        /// <summary>
        /// Instance of the class. Lazy initialization
        /// </summary>
        private static readonly FileMngr instance = new FileMngr();

        /// <summary>
        /// Logger declaration
        /// </summary>
        private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        #endregion Constants

        #region Initialization
        /// <summary>
        /// Prevents a default instance of the FileMngr class from being created.
        /// </summary>
        private FileMngr()
        {
        }

        /// <summary>
        /// Gets the reference to the object here.
        /// </summary>
        public static FileMngr Instance
        {
            get
            {
                return instance;
            }
        }
        #endregion Initialization

        #region Public Methods
        /// <summary>
        /// Loads a list of files that correspond to a mask
        /// </summary>
        /// <param name="mask">Search mask</param>
        /// <param name="path">Search path</param>
        /// <param name="recursive">If true, searches subdirectories too</param>
        /// <returns>A list of files found. If there was an error, null is returned</returns>
        public List<string> GetFileList(string mask, string path, bool recursive)
        {
            if (string.IsNullOrEmpty(mask))
            {
                mask = "*.*";
            }

            if (string.IsNullOrEmpty(path))
            {
                path = Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath);
            }
            //else
            //{
            //    path = Path.Combine(Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath), path);
            //}

            try
            {
                if (!Directory.Exists(path))
                {
                    log.WarnFormat("Could not load files from '{0}' because dir does no exist", path);
                    return new List<string>();
                }

                string[] files;

                if (recursive)
                {
                    files = System.IO.Directory.GetFiles(path, mask, SearchOption.AllDirectories);
                }
                else
                {
                    files = System.IO.Directory.GetFiles(path, mask, SearchOption.TopDirectoryOnly);
                }

                return files.ToList<string>();
            }
            catch (Exception ex)
            {
                log.Error(ex);
                return null;
            }
        }

        /// <summary>
        /// Loads a list of directories that correspond to a mask
        /// </summary>
        /// <param name="mask">Search mask</param>
        /// <param name="path">Search path</param>
        /// <param name="recursive">If true, searches subdirectories too</param>
        /// <returns>A list of files found. If there was an error, null is returned</returns>
        public List<string> GetDirectoryList(string mask, string path, bool recursive)
        {
            if (string.IsNullOrEmpty(mask))
            {
                mask = "*";
            }

            try
            {
                string[] directories;

                if (recursive)
                {
                    directories = System.IO.Directory.GetDirectories(path, mask, SearchOption.AllDirectories);
                }
                else
                {
                    directories = System.IO.Directory.GetDirectories(path, mask, SearchOption.TopDirectoryOnly);
                }

                return directories.ToList<string>();
            }
            catch (Exception ex)
            {
                log.Error(ex);
                return null;
            }
        }

        /// <summary>
        /// Extracts the name of the file from a full path
        /// </summary>
        /// <param name="path">The path and name of the file that needs to be processed</param>
        /// <returns>The full name of the file</returns>
        public string ExtractFileName(string path)
        {
            if (string.IsNullOrEmpty(path))
            {
                return string.Empty;
            }

            // Create the FileInfo object
            FileInfo fi = new FileInfo(path);

            // Return the file name
            return fi.Name;
        }

        /// <summary>
        /// Extracts the name of the file (without extension)
        /// </summary>
        /// <param name="fileName">The path and name of the file that needs to be processed</param>
        /// <returns>Name of the file without extension</returns>
        public string ExtractNameFromFilename(string fileName)
        {
            if (string.IsNullOrEmpty(fileName))
            {
                return string.Empty;
            }

            // Get the name of the file
            string baseFileName = FileMngr.Instance.ExtractFileName(fileName.Trim());

            // Remove the extension and return the string
            if (baseFileName.IndexOf(".") == -1)
            {
                return baseFileName;
            }
            else
            {
                return baseFileName.Substring(0, baseFileName.LastIndexOf('.'));
            }
        }

        /// <summary>
        /// Extracts the full path of the directory or filename
        /// </summary>
        /// <param name="fullFilename">The path and name of the file that needs to be processed</param>
        /// <returns>Dir in which the file is located</returns>
        public string ExtractFileDir(string fullFilename)
        {
            if (string.IsNullOrEmpty(fullFilename))
            {
                return string.Empty;
            }

            // Create the FileInfo object
            FileInfo fi = new FileInfo(fullFilename);

            // Return the file name
            return fi.Directory.FullName;
        }

        /// <summary>
        /// Extracts the extansion of the file
        /// </summary>
        /// <param name="fullFilename">The path and name of the file that needs to be processed</param>
        /// <returns>Extension of the file</returns>
        public string ExtractFileExtension(string fullFilename)
        {
            if (string.IsNullOrEmpty(fullFilename))
            {
                return string.Empty;
            }

            // Create the FileInfo object
            FileInfo fi = new FileInfo(fullFilename);

            // Return the file name
            return fi.Extension;
        }

        /// <summary>
        /// Converts a dir to relative to another dir
        /// </summary>
        /// <param name="mainDirPath">The base dir, the parent of the absoluteFilePath</param>
        /// <param name="absoluteFilePath">The full path (Longer than mainDirPath)</param>
        /// <returns>Relative path created from mainDirPath and absoluteFilePath
        /// C:\a\b and C:\a\b\c\x.txt -> .\c\x.txt
        /// </returns>
        public string RelativeDir(string mainDirPath, string absoluteFilePath)
        {
            string[] firstPathParts = mainDirPath.Trim(Path.DirectorySeparatorChar).Split(Path.DirectorySeparatorChar);
            string[] secondPathParts = absoluteFilePath.Trim(Path.DirectorySeparatorChar).Split(Path.DirectorySeparatorChar);
            int sameCounter = 0;

            for (int i = 0; i < Math.Min(firstPathParts.Length, secondPathParts.Length); i++)
            {
                if (!firstPathParts[i].ToLower().Equals(secondPathParts[i].ToLower()))
                {
                    break;
                }

                sameCounter++;
            }

            if (sameCounter == 0)
            {
                return absoluteFilePath;
            }

            string newPath = String.Empty;

            for (int i = sameCounter; i < firstPathParts.Length; i++)
            {
                if (i > sameCounter)
                {
                    newPath += Path.DirectorySeparatorChar;
                }

                newPath += "..";
            }

            if (newPath.Length == 0)
            {
                newPath = ".";
            }

            for (int i = sameCounter; i < secondPathParts.Length; i++)
            {
                newPath += Path.DirectorySeparatorChar;
                newPath += secondPathParts[i];
            }

            return newPath;
        }
        #endregion Public Methods
    }
}
